package com.ruoyi.business.sundry.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.ruoyi.business.base.PageParam;
import com.ruoyi.business.sundry.domain.JbRawMaterialAudit;
import com.ruoyi.business.sundry.domain.JbRawMaterialAuditRecord;
import com.ruoyi.business.sundry.domain.JbRawMaterialPriceHistory;
import com.ruoyi.business.sundry.domain.vo.JbMaterialPriceImportAdd;
import com.ruoyi.business.sundry.service.*;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessErrorEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.system.service.ISysUserService;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.business.base.JoBaseServiceImpl;
import com.ruoyi.business.sundry.mapper.JbRawMaterialPriceMapper;
import com.ruoyi.business.sundry.domain.JbRawMaterialPrice;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 原材料价格Service业务层处理
 *
 * @author ruoyi
 * @date 2024-10-11
 */
@Service
public class JbRawMaterialPriceServiceImpl
        extends JoBaseServiceImpl<JbRawMaterialPriceMapper, JbRawMaterialPrice>
        implements JbRawMaterialPriceService
{
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private JbRawMaterialAuditService jbRawMaterialAuditService;
    @Autowired
    private JbRawMaterialAuditRecordService jbRawMaterialAuditRecordService;
    @Autowired
    private JbRawMaterialPriceHistoryService jbRawMaterialPriceHistoryService;
    @Autowired
    private JbProductRecipeService jbProductRecipeService;

    @Override
    public IPage<JbRawMaterialPrice> pageList(PageParam page, JbRawMaterialPrice jbRawMaterialPrice)
    {
        LambdaQueryWrapper<JbRawMaterialPrice> select = new LambdaQueryWrapper<>();
        select.ge(StringUtils.isNotBlank(page.getStartTime()), JbRawMaterialPrice::getUpdateTime, page.getStartTime())
                .le(StringUtils.isNotBlank(page.getEndTime()), JbRawMaterialPrice::getUpdateTime, page.getEndTime())
                .and(StringUtils.isNotBlank(page.getKeyword()), a ->
                        a.like(JbRawMaterialPrice::getMaterialName, page.getKeyword()).or()
                                .like(JbRawMaterialPrice::getMaterialId, page.getKeyword()).or()
                                .like(JbRawMaterialPrice::getCurrentPrice, page.getKeyword()))
                .orderByDesc(JbRawMaterialPrice::getUpdateTime);
        IPage<JbRawMaterialPrice> pageVo = this.page(page.b(), select);
        if (ObjectUtils.isNotEmpty(pageVo) && ObjectUtils.isNotEmpty(pageVo.getRecords()))
        {
            List<Long> collect = pageVo.getRecords().stream().map(JbRawMaterialPrice::getUpdateBy).collect(Collectors.toList());
            List<SysUser> list = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getUserId, collect)
                    .select(SysUser::getUserName,SysUser::getUserId));
            Map<Long, String> collect1 = list.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getUserName));
            pageVo.getRecords().forEach(a ->a.setUpdatePerson(collect1.get(a.getUpdateBy())));
        }
        return pageVo;
    }

    @Override
    @Transactional
    public Boolean saveInfo(JbRawMaterialPrice jbRawMaterialPrice)
    {
        BigDecimal latestPrice = jbRawMaterialPrice.getLatestPrice();
        //暂时不填，审核通过后再更新数据
        jbRawMaterialPrice.setLatestPrice(null);
        if (ObjectUtils.isNotEmpty(latestPrice))
        {
            //新增时候，增加了价格，则添加审核，审核通过，则显示价格
            jbRawMaterialPrice.setAuditStatus(Constants.PUBLIC_NUMBER_2);
        }
        boolean save = this.save(jbRawMaterialPrice);
        if (ObjectUtils.isNotEmpty(latestPrice))
        {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            JbRawMaterialAudit materialAudit=new JbRawMaterialAudit();
            materialAudit.setAuditNumber(getCode());
            materialAudit.setMaterialName(jbRawMaterialPrice.getMaterialName());
            materialAudit.setAuditOperStatus(Constants.PUBLIC_NUMBER_1);
            materialAudit.setSubmitterId(loginUser.getUserId());
            Date date=new Date();
            materialAudit.setSubmitterTime(date);
            jbRawMaterialAuditService.save(materialAudit);
            JbRawMaterialAuditRecord jbRawMaterialAuditRecord=new JbRawMaterialAuditRecord();
            jbRawMaterialAuditRecord.setAuditId(materialAudit.getId());
            jbRawMaterialAuditRecord.setMaterialPriceId(jbRawMaterialPrice.getId());
            jbRawMaterialAuditRecord.setMaterialName(jbRawMaterialPrice.getMaterialName());
            jbRawMaterialAuditRecord.setMaterialId(jbRawMaterialPrice.getMaterialId());
            jbRawMaterialAuditRecord.setLatestPrice(latestPrice);
            jbRawMaterialAuditRecord.setAuditOperStatus(Constants.PUBLIC_NUMBER_1);
            jbRawMaterialAuditRecord.setSubmitterId(loginUser.getUserId());
            jbRawMaterialAuditRecord.setSubmitterTime(date);
            jbRawMaterialAuditRecordService.save(jbRawMaterialAuditRecord);

        }
        return save;
    }

    @Override
    public Boolean importData(List<JbMaterialPriceImportAdd> jbRawMaterialPrice)
    {
        List<String> collect = jbRawMaterialPrice.stream().map(JbMaterialPriceImportAdd::getMaterialId).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(collect))
        {
            throw new ServiceException(BusinessErrorEnum.CODE_ERROR_20009);
        }
        HashSet set = new HashSet<>(collect);
        if (collect.size()!=set.size())
        {
            throw new ServiceException(BusinessErrorEnum.CODE_ERROR_20010);
        }
        long count = this.count(Wrappers.lambdaQuery(JbRawMaterialPrice.class).in(JbRawMaterialPrice::getMaterialId, collect));
        if (count>0l)
        {
            throw new ServiceException(BusinessErrorEnum.CODE_ERROR_20011);
        }
        List<JbRawMaterialPrice> addList = BeanUtil.copyToList(jbRawMaterialPrice, JbRawMaterialPrice.class);
        return this.saveBatch(addList);
    }

    @Override
    @Transactional
    public Boolean batchUpdateInfo(List<JbMaterialPriceImportAdd> jbRawMaterialPrices)
    {

        int size = jbRawMaterialPrices.stream()
                .filter(a -> ObjectUtils.isEmpty(a.getLatestPrice())).collect(Collectors.toList()).size();
        //验证价格是否有空的
        if (size>0)
        {
            throw new ServiceException(BusinessErrorEnum.CODE_ERROR_20015);
        }
        List<String> collect = jbRawMaterialPrices.stream().map(JbMaterialPriceImportAdd::getMaterialId).collect(Collectors.toList());
        HashSet set = new HashSet<>(collect);
        //验证原材料id是否有重复
        if (collect.size()!=set.size())
        {
            throw new ServiceException(BusinessErrorEnum.CODE_ERROR_20010);
        }
        List<JbRawMaterialPrice> countList = this.list(Wrappers.lambdaQuery(JbRawMaterialPrice.class).in(JbRawMaterialPrice::getMaterialId, collect)
                .select(JbRawMaterialPrice::getId,JbRawMaterialPrice::getMaterialId,JbRawMaterialPrice::getMaterialName,JbRawMaterialPrice::getAuditStatus));
        //验证原材料id是否存在
        if (jbRawMaterialPrices.size()>countList.size())
        {
            throw new ServiceException(BusinessErrorEnum.CODE_ERROR_20013);
        }
        //验证原材料id是否有提交审核没有处理的。
        long statusCount =countList.stream().filter(a ->a.getAuditStatus().equals(Constants.PUBLIC_NUMBER_2)).count();
        if (statusCount>0)
        {
            throw new ServiceException(BusinessErrorEnum.CODE_ERROR_20014);
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        //添加审核记录，更新原材料数据
        JbRawMaterialAudit materialAudit=new JbRawMaterialAudit();
        materialAudit.setAuditNumber(getCode());
        materialAudit.setAuditOperStatus(Constants.PUBLIC_NUMBER_1);
        materialAudit.setSubmitterId(loginUser.getUserId());
        Date date=new Date();
        materialAudit.setSubmitterTime(date);
        materialAudit.setMaterialName(countList.get(0).getMaterialName());
        if (countList.size()>1)
        {
            materialAudit.setMaterialName(materialAudit.getMaterialName()+"等");
        }
        jbRawMaterialAuditService.save(materialAudit);
        Map<String, BigDecimal> mapPrice = jbRawMaterialPrices.stream().collect(Collectors.toMap(JbMaterialPriceImportAdd::getMaterialId, JbMaterialPriceImportAdd::getLatestPrice));
        //添加审核记录，原材料id数据
        List<JbRawMaterialAuditRecord> updateList= Lists.newArrayList();
        List<JbRawMaterialPrice> updaPriceList= Lists.newArrayList();
        for (JbRawMaterialPrice price:countList)
        {
            //添加审核原材料id
            JbRawMaterialAuditRecord update=new JbRawMaterialAuditRecord();
            update.setAuditId(materialAudit.getId());
            update.setMaterialPriceId(price.getId());
            update.setMaterialId(price.getMaterialId());
            update.setMaterialName(price.getMaterialName());
            update.setLatestPrice(mapPrice.get(price.getMaterialId()));
            update.setAuditOperStatus(Constants.PUBLIC_NUMBER_1);
            update.setSubmitterId(loginUser.getUserId());
            update.setSubmitterTime(date);
            updateList.add(update);
            //修改原材料的状态
            JbRawMaterialPrice updatePrice=new JbRawMaterialPrice();
            updatePrice.setId(price.getId());
            updatePrice.setAuditStatus(Constants.PUBLIC_NUMBER_2);
            updaPriceList.add(updatePrice);
        }
        jbRawMaterialAuditRecordService.saveBatch(updateList);
        this.updateBatchById(updaPriceList);
        return true;
    }

    @Override
    public IPage<JbRawMaterialAudit> auditList(PageParam page, JbRawMaterialAudit jbRawMaterialAudit)
    {
        LambdaQueryWrapper<JbRawMaterialAudit> select = new LambdaQueryWrapper<>();
        select.ge(StringUtils.isNotBlank(page.getStartTime()), JbRawMaterialAudit::getSubmitterTime, page.getStartTime())
                .le(StringUtils.isNotBlank(page.getEndTime()), JbRawMaterialAudit::getSubmitterTime, page.getEndTime())
                .and(StringUtils.isNotBlank(page.getKeyword()), a ->
                        a.like(JbRawMaterialAudit::getMaterialName, page.getKeyword()).or()
                                .like(JbRawMaterialAudit::getAuditNumber, page.getKeyword()))
                .orderByDesc(JbRawMaterialAudit::getId);
        IPage<JbRawMaterialAudit> pageList = jbRawMaterialAuditService.page(page.b(), select);
        if (ObjectUtils.isNotEmpty(pageList) && ObjectUtils.isNotEmpty(pageList.getRecords()))
        {
            List<Long> collect = pageList.getRecords().stream().map(JbRawMaterialAudit::getSubmitterId).collect(Collectors.toList());
            List<SysUser> list = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getUserId, collect)
                    .select(SysUser::getUserName,SysUser::getUserId));
            Map<Long, String> collect1 = list.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getUserName));
            pageList.getRecords().forEach(a ->a.setSubmitterName(collect1.get(a.getUpdateBy())));
        }
        return pageList;
    }

    @Override
    public List<JbRawMaterialAuditRecord> auditRecrodList(PageParam page, JbRawMaterialAuditRecord jbRawMaterialAuditRecord)
    {
        LambdaQueryWrapper<JbRawMaterialAuditRecord> select = new LambdaQueryWrapper<>();
        select.eq(JbRawMaterialAuditRecord::getAuditId,jbRawMaterialAuditRecord.getAuditId());
        List<JbRawMaterialAuditRecord> pageVo = jbRawMaterialAuditRecordService.list(select);
        if (ObjectUtils.isNotEmpty(pageVo))
        {
            List<Long> collect = pageVo.stream().map(JbRawMaterialAuditRecord::getSubmitterId).collect(Collectors.toList());
            List<SysUser> list = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getUserId, collect)
                    .select(SysUser::getUserName,SysUser::getUserId));
            Map<Long, String> collect1 = list.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getUserName));
            pageVo.forEach(a ->a.setSubmitterName(collect1.get(a.getUpdateBy())));
        }
        return pageVo;
    }

    @Override
    @Transactional
    public Boolean updateAuditStatus(JbRawMaterialAudit jbRawMaterialAudit)
    {
        JbRawMaterialAudit updateAudit=new JbRawMaterialAudit();
        updateAudit.setId(jbRawMaterialAudit.getId());
        updateAudit.setAuditOperStatus(Constants.PUBLIC_NUMBER_0);
        updateAudit.setAuditStatus(jbRawMaterialAudit.getAuditStatus());
        updateAudit.setAuditRemark(jbRawMaterialAudit.getAuditRemark());
        jbRawMaterialAuditService.updateById(updateAudit);

        List<JbRawMaterialAuditRecord> recordsList = jbRawMaterialAuditRecordService.list(Wrappers.lambdaQuery(JbRawMaterialAuditRecord.class).eq(JbRawMaterialAuditRecord::getAuditId, jbRawMaterialAudit.getId()));
        List<JbRawMaterialAuditRecord> recordIds=Lists.newArrayList();
        List<JbRawMaterialPrice> priceIds=Lists.newArrayList();
        List<JbRawMaterialPriceHistory> historyIds=Lists.newArrayList();
        Map<Long,BigDecimal> recipeData= Maps.newHashMap();
        recordsList.forEach(a ->{
            //更新审核记录的数据
            JbRawMaterialAuditRecord record=new JbRawMaterialAuditRecord();
            record.setId(a.getId());
            record.setAuditStatus(jbRawMaterialAudit.getAuditStatus());
            record.setAuditOperStatus(Constants.PUBLIC_NUMBER_0);
            record.setAuditRemark(jbRawMaterialAudit.getAuditRemark());
            recordIds.add(record);
            //更新原材料最新价格
            JbRawMaterialPrice price=new JbRawMaterialPrice();
            if (Constants.PUBLIC_NUMBER_0.equals(jbRawMaterialAudit.getAuditStatus()))
            {
                //审核通过
                //添加历史数据
                JbRawMaterialPriceHistory history=new JbRawMaterialPriceHistory();
                history.setMaterialPriceId(a.getMaterialPriceId());
                history.setMaterialId(a.getMaterialId());
                history.setMaterialName(a.getMaterialName());
                history.setLatestPrice(a.getLatestPrice());
                history.setAuditStatus(jbRawMaterialAudit.getAuditStatus());
                historyIds.add(history);
                //通过后才更新价格
                price.setLatestPrice(a.getLatestPrice());
                recipeData.put(a.getMaterialPriceId(),a.getLatestPrice());
            }
            price.setId(a.getMaterialPriceId());
            price.setAuditStatus(jbRawMaterialAudit.getAuditStatus());
            priceIds.add(price);

        });
        //批量更新审核记录
        jbRawMaterialAuditRecordService.updateBatchById(recordIds);
        //更新原料
        this.updateBatchById(priceIds);
        //添加历史
        if (ObjectUtils.isNotEmpty(historyIds))
        {
            jbRawMaterialPriceHistoryService.saveBatch(historyIds);
        }
        //更新配方使用的原料计算的实时成本
        if (ObjectUtils.isNotEmpty(recipeData))
        {
            jbProductRecipeService.updateRealTimeCost(recipeData);
        }
        return true;
    }

    @Override
    @Transactional
    public Boolean updateInfo(JbRawMaterialPrice jbRawMaterialPrices)
    {
        JbRawMaterialPrice byId = this.getById(jbRawMaterialPrices.getId());
        if (Constants.PUBLIC_NUMBER_2.equals(byId.getAuditStatus()))
        {
            throw new ServiceException(BusinessErrorEnum.CODE_ERROR_20012);
        }
        jbRawMaterialPrices.setMaterialId(null);
        if (ObjectUtils.isEmpty(byId.getLatestPrice()) || byId.getLatestPrice().compareTo(jbRawMaterialPrices.getLatestPrice())!=0)
        {
            //最新价格，不相等，则审核
            jbRawMaterialPrices.setAuditStatus(Constants.PUBLIC_NUMBER_2);
            LoginUser loginUser = SecurityUtils.getLoginUser();
            //添加审核信息
            JbRawMaterialAudit materialAudit=new JbRawMaterialAudit();
            materialAudit.setAuditNumber(getCode());
            materialAudit.setMaterialName(byId.getMaterialName());
            materialAudit.setAuditOperStatus(Constants.PUBLIC_NUMBER_1);
            materialAudit.setSubmitterId(loginUser.getUserId());
            Date date=new Date();
            materialAudit.setSubmitterTime(date);
            jbRawMaterialAuditService.save(materialAudit);
            //添加原料记录信息
            JbRawMaterialAuditRecord jbRawMaterialAuditRecord=new JbRawMaterialAuditRecord();
            jbRawMaterialAuditRecord.setAuditId(materialAudit.getId());
            jbRawMaterialAuditRecord.setMaterialPriceId(byId.getId());
            jbRawMaterialAuditRecord.setMaterialName(byId.getMaterialName());
            jbRawMaterialAuditRecord.setMaterialId(byId.getMaterialId());
            jbRawMaterialAuditRecord.setLatestPrice(jbRawMaterialPrices.getLatestPrice());
            jbRawMaterialAuditRecord.setAuditOperStatus(Constants.PUBLIC_NUMBER_1);
            jbRawMaterialAuditRecord.setSubmitterId(loginUser.getUserId());
            jbRawMaterialAuditRecord.setSubmitterTime(date);
            jbRawMaterialAuditRecordService.save(jbRawMaterialAuditRecord);
            //暂时不填，审核通过后再更新数据
            jbRawMaterialPrices.setLatestPrice(null);
        }
        boolean b = this.updateById(jbRawMaterialPrices);
        return b;
    }
    /**
     * 获取客户编码
     *
     * @return
     */
    private String getCode()
    {
        int attemptCount = 10;
        String kh = Strings.EMPTY;
        for (int i = 0; i <= attemptCount; i++)
        {
            kh = DateUtils.generateSerialNumber("", 2);
            long count = jbRawMaterialAuditService.count(Wrappers.lambdaQuery(JbRawMaterialAudit.class).eq(JbRawMaterialAudit::getAuditNumber, kh));
            if (count == 0)
            {
                break;
            }
            if (attemptCount == i)
            {
                throw new ServiceException();
            }
        }
        return kh;
    }
}
